package com.esdk.utils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.esdk.esdk;
import com.esdk.sql.orm.IResultSet;
import com.esdk.sql.orm.IRow;

/***
 * 返回类，用于返回错误标志和错误描述，可以追加错误信息，嵌套多个返回类等功能。
 * 
 * @author Franky
 */
public class Response implements Serializable {
	private StringBuffer resultMsg=new StringBuffer(),errMsg=new StringBuffer();
	private boolean success;
	private String errorPrefix="",errorPostix="！";
	private String delimiter=" | ";
	private static String _SuccessMsg="成功",_ErrorMsg="失败";
	private JSONObject attributes=new JSONObject(true);

	public Response(){
	}

	public Response(String jsonStr) {
		if(isResponse(jsonStr)){
			JSONObject jo=esdk.json.toJsonObject(jsonStr);
			setSuccess(jo.getBooleanValue("success"),jo.getString("msg"),jo.getString("msg"));
			jo.remove("success");
			jo.remove("msg");
			for(Iterator iter=jo.keySet().iterator();iter.hasNext();) {
				String key=iter.next().toString();
				put(key,jo.getString(key));
			}
		}else{
			setErrMsg(jsonStr);
		}
	}
	
	public Response(boolean success){
		setSuccess(success);
	}

	public Response(Throwable e){
		setThrowable(e);
	}

	public Response(boolean success,String msg){
		setMsg(msg,success);
	}

	public Response setErrorPrefix(String errorPrefix){
		this.errorPrefix=errorPrefix;
		return this;
	}

	public Response setErrorPostix(String errorPrefix){
		errorPostix=errorPrefix;
		return this;
	}
	public Response(boolean success,String successMsg,String errMsg){
		setSuccess(success,successMsg,errMsg);
	}

	public String toString(){
		return toJson().toString();
	}

	public Response setThrowable(Throwable ex){
		success=false;
		resultMsg.delete(0,resultMsg.length());
		if(ex.getMessage()!=null)
			errMsg.append(ex.getMessage());
		else
			errMsg.append(ex.toString());
		return this;
	}

	public Response setSuccessMsg(String successMsg){
		return setMsg(successMsg,true);
	}

	public Response setMsg(String msg){
		setMsg(msg,this.success);
		return this;
	}
	
	public Response setMsg(String msg,boolean success){
		if(success){
			resultMsg.delete(0,resultMsg.length());
			if(msg!=null)
				resultMsg.append(msg);
			this.success=true;
		}else
			appendErrMsg(msg);
		return this;
	}

	public boolean hasErrMsg(){
		return errMsg!=null&&errMsg.length()>0;
	}

	public boolean hasReturnMsg(){
		return resultMsg!=null&&resultMsg.length()>0;
	}

	public Response appendErrMsg(String errorMsg){
		if(!EasyStr.isBlank(errorMsg)){
			success=false;
			if(errMsg.length()==0){
				errMsg.append(errorMsg);
			}else
				errMsg.append(delimiter).append(errorMsg);
		}
		return this;
	}

	public Response appendMsg(String msg){
		return appendReturnMsg(msg);
	}
	
	public Response appendReturnMsg(String msg){
		if(this.resultMsg.length()==0)
			this.resultMsg.append(msg);
		else if(esdk.str.isValid(msg))
			this.resultMsg.append(delimiter).append(msg);
		return this;
	}

	public Response appendUniqueErrMsg(String errorMsg){
		if(errMsg.indexOf(errorMsg)<0)
			appendErrMsg(errorMsg);
		return this;
	}

	public Response appendUniqueMsg(String msg){
		if(resultMsg.indexOf(msg)<0)
			appendMsg(msg);
		return this;
	}
	
	public Response appendUnique(Response ri){
		if(ri.success&&!this.getMsg().contains(ri.getMsg()) || !ri.success&&!this.getErrMsg().contains(ri.getErrMsg()))
			this.append(ri);
		return this;
	}
	

	public Response setErrMsg(String errorMsg){
		errMsg.delete(0,errMsg.length());
		if(!EasyStr.isBlank(errorMsg)){
			success=false;
			errMsg.append(errorMsg);
		}
		return this;
	}

	public String getMsg(){
		if(success)
			return resultMsg.toString();
		else
			return getErrMsg();
	}

	public String getErrMsg(){
		if(errMsg.length()>0&&esdk.str.isValid(errorPostix)&&errMsg.lastIndexOf(errorPostix)<0)
			errMsg.append(errorPostix);
		if(esdk.str.isValid(errorPrefix)&&errMsg.indexOf(errorPrefix)<0)
			errMsg.insert(0,errorPrefix);
		return errMsg.toString();
	}

	public void clear(){
		errMsg.delete(0,errMsg.length());
		resultMsg.delete(0,resultMsg.length());
		success=false;
	}

	public boolean success(){
		return success;
	}

	public Response setSuccess(boolean success){
		this.success=success;
		return this;
	}

	public Response setSuccess(boolean success,String successMsg,String errMsg){
		if(success)
			setMsg(successMsg,true);
		else
			setErrMsg(errMsg);
		return this;
	}

	public Response setSuccess(boolean success,String successMsg){
		if(success)
			setMsg(successMsg,true);
		else
			setErrMsg(esdk.obj.or(successMsg,_ErrorMsg));
		return this;
	}

	public Response setValid(boolean v){
		return setSuccess(v);
	}

	public Response append(String jsonObj) {
		append(new Response(jsonObj));
		return this;
	}

	/**只要其中实例一个返回true，就认为是成功，正常默认是and，只要一个实例是false，就认为是失败*/
	public Response appendOr(Response ri) {
		if(ri==null||ri==this)
			return this;
		if(this!=ri){
			if(!ri.success()&&ri.errMsg.length()>0)
				this.appendUniqueErrMsg(ri.errMsg.toString());
			else if(EasyObj.isValid(ri.resultMsg.toString()))
				appendUniqueMsg(ri.getMsg());
			setSuccess(this.success||ri.success);
		}
		this.attributes.putAll(ri.attributes);
		return this;
	}
	
	public Response append(Response ri){
		if(ri==this||ri==null)
			return this;
		if(this!=ri){
			if(!ri.success()&&ri.errMsg.length()>0)
				this.appendUniqueErrMsg(ri.errMsg.toString());
			else if(EasyObj.isValid(ri.resultMsg.toString()))
				appendUniqueMsg(ri.getMsg());
			setSuccess(this.success&&ri.success);
		}
		this.attributes.putAll(ri.attributes);
		return this;
	}

	public Response append(boolean success){
		return append(new Response(success));
	}

	public Response put(String key,String value){
		attributes.put(key,value);
		return this;
	}

	public Response putAll(Map value){
		attributes.putAll(value);
		return this;
	}
	
	public Response put(String key,JSONArray jsonArray){
		attributes.put(key,jsonArray);
		return this;
	}
	
	public Response put(String key,JSONObject jsonObject){
		attributes.put(key,jsonObject);
		return this;
	}

	public Response put(String key,boolean value){
		attributes.put(key,value);
		return this;
	}

	public Response put(String key,Long value){
		attributes.put(key,esdk.sql.isSnowId(value)?value.toString():value);
		return this;
	}

	public Response put(String key,Number value){
		attributes.put(key,value);
		return this;
	}

	public Response put(String key,Integer value){
		attributes.put(key,value);
		return this;
	}

	public Response put(String key,IResultSet rs){
		if(rs==null)
			return this;
		attributes.put(key,rs.toMapList(true));
		return this;
	}
	
	public Response put(String key,IRow row){
		if(row==null)
			return this;
		attributes.put(key,row.toJsonObject(true));
		return this;
	}

	public <T>T getData(Class<T> clazz){
		JSONObject jo=attributes.getJSONObject("data");
		if (esdk.obj.isEmpty(jo)) {
			return null;
		}
		return JSONUtil.toBean(jo.toJSONString(),clazz);
	}

	public <T>List<T> getDataList(Class<T> clazz){
		JSONArray ja=attributes.getJSONArray("data");
		if (esdk.obj.isEmpty(ja)) {
			return null;
		}
		return JsonUtils.toBeanList(ja,clazz);
	}

	public Response setData(Object data){
		return setData(data, false);
	}

	/**
	 *
	 * @param data
	 * @param isConvertSnowIdToStr 是否自动转换雪花ID为String
	 * @return
	 */
	public Response setData(Object data, boolean isConvertSnowIdToStr) {
		if (isConvertSnowIdToStr) {
			attributes.put("data",esdk.json.toJSON(esdk.bean.toMap((Serializable) data, BeanToMapConfig.renderConfig())));
		} else {
			attributes.put("data",esdk.json.toJSON(data));
		}
		return this;
	}


	/**
	 * @param bean 应为bean对象，不要随便塞一些奇怪的对象，容易出错，注意：会自动把雪花id的Long类型转成字符串类型
	 * */
	public Response put(String key,Serializable bean){
		if(bean==null)
			return this;
		attributes.put(key,EasyBean.toMap(bean,BeanToMapConfig.renderConfig()));
		return this;
	}


	public Response put(String key,List list){
		if(list!=null&&list.size()>0){
			if(list.get(0) instanceof IResultSet) {
				List<List<Map>> mapList=new ArrayList(list.size());
				for(int i=0;i<list.size();i++){
					mapList.add(((IResultSet)list.get(i)).toMapList(true));
				}
				attributes.put(key,mapList);
			}else if(list.get(0) instanceof IRow){
				List<JSONObject> rowList=new ArrayList(list.size());
				for(int i=0;i<list.size();i++){
					rowList.add(((IRow)list.get(i)).toJsonObject(true));
				}
				attributes.put(key,rowList);
			}
		}else {
			attributes.put(key,list);
		}
		return this;
	}
	
	public Object get(String key){
		return attributes.get(key);
	}
	
	public String getString(String key){
		return (String)attributes.get(key);
	}

	public Response setDelimiter(String value){
		this.delimiter=value;
		return this;
	}

	public JSONObject toJson(){
		JSONObject result=new JSONObject(true);
		result.put("success", success());
		if(esdk.str.isValid(getMsg()))
			result.put("msg", getMsg());
		result.putAll(attributes);
		return result;
	}

	public static boolean isResponse(String res) {
		return res!=null&&res.matches(".*?\"success\":(true|false).*?");
	}

	public static void main(String[] args){
		esdk.tool.assertEquals(new Response(true).toString(),"{\"success\":true}");
		esdk.tool.assertEquals(new Response(false).toString(),"{\"success\":false}");
		esdk.tool.assertEquals(new Response(true).append(new Response(false)).toString(),"{\"success\":false}");
		esdk.tool.assertEquals(new Response(true).append(new Response(true)).toString(),"{\"success\":true}");
		esdk.tool.assertEquals(new Response(false,"测试重复错误").append(new Response(false,"测试重复错误")).toString(),"{\"success\":false,\"msg\":\"测试重复错误！\"}");
		Response ri=new Response(false,"除零错误");
		esdk.tool.assertEquals(ri.toString(),"{\"success\":false,\"msg\":\"除零错误！\"}");
		esdk.tool.assertEquals(new Response(true).setErrMsg("金额不能为空").toString(),"{\"success\":false,\"msg\":\"金额不能为空！\"}");
		ri.put("id",1818623425868042240L);
		esdk.tool.assertEquals(ri.toString(),"{\"success\":false,\"msg\":\"除零错误！\",\"id\":\"1818623425868042240\"}");
		JSONObject jo=new JSONObject();
		jo.put("userId",1234);
		jo.put("userName","张三");
		ri.put("user",jo);
//		System.out.println(ri);
		esdk.tool.assertEquals(esdk.json.toJSON(ri.toString()).toString(),"{\"success\":false,\"msg\":\"除零错误！\",\"id\":\"1818623425868042240\",\"user\":{\"userName\":\"张三\",\"userId\":1234}}");
		ri=new Response(false);
		ri.put("detail","详细内容");
		esdk.tool.assertEquals(ri.toString(),"{\"success\":false,\"detail\":\"详细内容\"}");
	}

}
